package com.design_mode;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Stack;


/**
 * Created by dustaple on 8/2/14.
 */
public class InterpreterPattern {

    private static HashMap<String, Integer> getValue(String exp) throws IOException {
        HashMap<String, Integer> var = new HashMap<String, Integer>();
        for (char ch : exp.toCharArray()) {
            if (ch != '+' && ch != '-') {
                if (!var.containsKey(String.valueOf(ch))) {
                    String val = new BufferedReader(new InputStreamReader(System.in)).readLine();
                    var.put(String.valueOf(ch), Integer.valueOf(val));
                }
            }
        }
        return var;
    }

    public static void main(String[] args) {
        HashMap<String, Integer> expression = new HashMap<String, Integer>();
        System.out.println("请输入要计算的表达式公式:");
        String tmpExpression = "";
        try {
            tmpExpression = new BufferedReader(new InputStreamReader(System.in)).readLine();
            if (!tmpExpression.isEmpty())
                expression = getValue(tmpExpression);
        } catch (IOException e) {
            e.printStackTrace();
        }

        if (!expression.isEmpty()) {
            Calculator cal = new Calculator(tmpExpression);
            System.out.println(cal.run(expression));
        }
    }
}

interface AbstractExpression<T extends Number> {
    T interprete(HashMap<String, T> var);
}

abstract class SymboExpression implements AbstractExpression {
    AbstractExpression left;
    AbstractExpression right;

    public SymboExpression(AbstractExpression left, AbstractExpression right) {
        this.left = left;
        this.right = right;
    }
}

class AddExpression extends SymboExpression {

    public AddExpression(AbstractExpression left, AbstractExpression right) {
        super(left, right);
    }

    @Override
    @SuppressWarnings("unchecked")
    public Number interprete(HashMap var) {
        Number a = super.left.interprete(var);
        Number b = super.right.interprete(var);
        if (a instanceof Byte) {
            return a.byteValue() + b.byteValue();
        } else if (a instanceof Short) {
            return a.shortValue() + b.shortValue();
        } else if (a instanceof Integer) {
            return a.intValue() + b.intValue();
        } else {
            return a.doubleValue() + b.doubleValue();
        }
    }
}

class NonterminalExpression implements AbstractExpression {
    private String key;

    public NonterminalExpression(String key) {
        this.key = key;
    }

    @Override
    public Number interprete(HashMap var) {
        return (Number) var.get(key);
    }
}

class Calculator {
    AbstractExpression expression;

    public Calculator(String exp) {
        Stack<AbstractExpression> stack = new Stack<AbstractExpression>();
        char chArray[] = exp.toCharArray();
        AbstractExpression left = null;
        AbstractExpression right = null;
        for (int i = 0; i < chArray.length; ++i) {
            switch (chArray[i]) {
                case '+':
                    left = stack.pop();
                    right = new NonterminalExpression(String.valueOf(chArray[++i]));
                    stack.push(new AddExpression(left, right));
                    break;
                case '-':
                default:
                    stack.push(new NonterminalExpression(String.valueOf(chArray[i])));
            }
        }
        this.expression = stack.pop();
    }

    @SuppressWarnings("unchecked")
    public Integer run(HashMap<String, Integer> var) {
        return (Integer) this.expression.interprete(var);
    }
}